package com.yunke.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunke.entity.YunkeAdmin;
import com.yunke.entity.dto.YunkeAdminDto;
import com.yunke.entity.dto.YunkeAdminLoginDto;
import com.yunke.entity.vo.YunkeAdminVo;
import com.yunke.mapper.YunkeAdminMapper;
import com.yunke.common.result.YunkeResult;
import com.yunke.common.util.YunkeTimeUtil;
import com.yunke.service.YunkeAdminService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 管理员Service实现类
 * 
 * @author yunke
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class YunkeAdminServiceImpl extends ServiceImpl<YunkeAdminMapper, YunkeAdmin> implements YunkeAdminService {

    private final YunkeAdminMapper adminMapper;
    private final HttpServletRequest request;

    @Override
    public YunkeResult<String> login(YunkeAdminLoginDto loginDto) {
        try {
            // 查询管理员
            YunkeAdmin admin = adminMapper.selectByUsername(loginDto.getUsername());
            if (admin == null) {
                return YunkeResult.error("用户名或密码错误");
            }

            // 检查账户状态
            if (admin.getAccountStatus() == 1) {
                return YunkeResult.error("账户已被禁用");
            }
            if (admin.getAccountStatus() == 2 && admin.getLockExpireTime() > System.currentTimeMillis()) {
                return YunkeResult.error("账户已被锁定，请稍后再试");
            }

            // 验证密码
            if (!BCrypt.checkpw(loginDto.getPassword(), admin.getPassword())) {
                // 更新密码错误次数
                int errorCount = admin.getPasswordErrorCount() + 1;
                Long lockTime = null;
                if (errorCount >= 5) {
                    lockTime = System.currentTimeMillis() + 30 * 60 * 1000; // 锁定30分钟
                    adminMapper.updatePasswordErrorCount(admin.getId(), errorCount, lockTime);
                    return YunkeResult.error("密码错误次数过多，账户已被锁定30分钟");
                } else {
                    adminMapper.updatePasswordErrorCount(admin.getId(), errorCount, null);
                    return YunkeResult.error("用户名或密码错误，还有" + (5 - errorCount) + "次机会");
                }
            }

            // 重置密码错误次数
            adminMapper.resetPasswordErrorCount(admin.getId());

            // 执行登录
            StpUtil.login(admin.getId());

            // 更新最后登录信息
            String clientIp = getClientIp();
            int loginCount = admin.getLoginCount() + 1;
            adminMapper.updateLastLoginInfo(admin.getId(), System.currentTimeMillis(), clientIp, loginCount);

            String tokenValue = StpUtil.getTokenValue();
            return YunkeResult.success("登录成功");

        } catch (Exception e) {
            log.error("管理员登录失败", e);
            return YunkeResult.error("登录失败");
        }
    }

    @Override
    public YunkeResult<Void> logout() {
        try {
            StpUtil.logout();
            return YunkeResult.success("登出成功");
        } catch (Exception e) {
            log.error("管理员登出失败", e);
            return YunkeResult.error("登出失败");
        }
    }

    @Override
    public YunkeResult<YunkeAdminVo> getCurrentAdmin() {
        try {
            Long adminId = StpUtil.getLoginIdAsLong();
            YunkeAdminVo adminVo = adminMapper.selectAdminVoById(adminId);
            if (adminVo == null) {
                return YunkeResult.error("管理员不存在");
            }
            return YunkeResult.success(adminVo);
        } catch (Exception e) {
            log.error("获取当前管理员信息失败", e);
            return YunkeResult.error("获取管理员信息失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> changePassword(String oldPassword, String newPassword) {
        try {
            Long adminId = StpUtil.getLoginIdAsLong();
            YunkeAdmin admin = getById(adminId);
            if (admin == null) {
                return YunkeResult.error("管理员不存在");
            }

            // 验证旧密码
            if (!BCrypt.checkpw(oldPassword, admin.getPassword())) {
                return YunkeResult.error("原密码错误");
            }

            // 加密新密码
            String hashedPassword = BCrypt.hashpw(newPassword, BCrypt.gensalt());
            admin.setPassword(hashedPassword);
            admin.setUpdateTime(System.currentTimeMillis());

            updateById(admin);
            return YunkeResult.success("密码修改成功");

        } catch (Exception e) {
            log.error("修改密码失败", e);
            return YunkeResult.error("修改密码失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> updateCurrentAdmin(YunkeAdminDto adminDto) {
        try {
            Long adminId = StpUtil.getLoginIdAsLong();
            YunkeAdmin admin = getById(adminId);
            if (admin == null) {
                return YunkeResult.error("管理员不存在");
            }

            // 更新基本信息
            if (StrUtil.isNotBlank(adminDto.getNickname())) {
                admin.setNickname(adminDto.getNickname());
            }
            if (StrUtil.isNotBlank(adminDto.getAvatar())) {
                admin.setAvatar(adminDto.getAvatar());
            }
            if (StrUtil.isNotBlank(adminDto.getEmail())) {
                admin.setEmail(adminDto.getEmail());
            }
            if (StrUtil.isNotBlank(adminDto.getMobile())) {
                admin.setMobile(adminDto.getMobile());
            }
            admin.setUpdateTime(System.currentTimeMillis());

            updateById(admin);
            return YunkeResult.success("信息更新成功");

        } catch (Exception e) {
            log.error("更新管理员信息失败", e);
            return YunkeResult.error("更新信息失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> createAdmin(YunkeAdminDto adminDto) {
        try {
            // 检查用户名是否存在
            if (existsByUsername(adminDto.getUsername(), null)) {
                return YunkeResult.error("用户名已存在");
            }

            // 创建管理员
            YunkeAdmin admin = new YunkeAdmin();
            BeanUtil.copyProperties(adminDto, admin);

            // 加密密码
            String hashedPassword = BCrypt.hashpw(adminDto.getPassword(), BCrypt.gensalt());
            admin.setPassword(hashedPassword);

            // 设置默认值
            admin.setAccountStatus(0);
            admin.setIsSuperAdmin(false);
            admin.setLoginCount(0);
            admin.setPasswordErrorCount(0);
            admin.setCreateTime(System.currentTimeMillis());
            admin.setUpdateTime(System.currentTimeMillis());

            // 设置创建人信息
            Long currentAdminId = StpUtil.getLoginIdAsLong();
            admin.setCreatorId(currentAdminId);

            save(admin);
            return YunkeResult.success("管理员创建成功");

        } catch (Exception e) {
            log.error("创建管理员失败", e);
            return YunkeResult.error("创建管理员失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> updateAdmin(YunkeAdminDto adminDto) {
        try {
            YunkeAdmin admin = getById(adminDto.getId());
            if (admin == null) {
                return YunkeResult.error("管理员不存在");
            }

            // 检查用户名是否存在（排除当前管理员）
            if (existsByUsername(adminDto.getUsername(), adminDto.getId())) {
                return YunkeResult.error("用户名已存在");
            }

            // 更新管理员信息
            BeanUtil.copyProperties(adminDto, admin, "id", "password", "createTime");
            
            // 如果有新密码，则更新密码
            if (StrUtil.isNotBlank(adminDto.getPassword())) {
                String hashedPassword = BCrypt.hashpw(adminDto.getPassword(), BCrypt.gensalt());
                admin.setPassword(hashedPassword);
            }
            
            admin.setUpdateTime(System.currentTimeMillis());
            updateById(admin);
            
            return YunkeResult.success("管理员信息更新成功");

        } catch (Exception e) {
            log.error("更新管理员失败", e);
            return YunkeResult.error("更新管理员失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> deleteAdmin(Long id) {
        try {
            YunkeAdmin admin = getById(id);
            if (admin == null) {
                return YunkeResult.error("管理员不存在");
            }

            // 检查是否为超级管理员
            if (admin.getIsSuperAdmin()) {
                return YunkeResult.error("不能删除超级管理员");
            }

            // 软删除
            admin.setStatus(1);
            admin.setUpdateTime(System.currentTimeMillis());
            updateById(admin);

            return YunkeResult.success("管理员删除成功");

        } catch (Exception e) {
            log.error("删除管理员失败", e);
            return YunkeResult.error("删除管理员失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> batchDeleteAdmin(List<Long> ids) {
        try {
            // 检查是否包含超级管理员
            List<YunkeAdmin> admins = listByIds(ids);
            boolean hasSuperAdmin = admins.stream().anyMatch(YunkeAdmin::getIsSuperAdmin);
            if (hasSuperAdmin) {
                return YunkeResult.error("批量删除中包含超级管理员，操作失败");
            }

            // 批量更新状态为删除
            for (Long id : ids) {
                YunkeAdmin admin = getById(id);
                if (admin != null && !admin.getIsSuperAdmin()) {
                    admin.setStatus(1);
                    admin.setUpdateTime(System.currentTimeMillis());
                    updateById(admin);
                }
            }
            return YunkeResult.success("批量删除成功");

        } catch (Exception e) {
            log.error("批量删除管理员失败", e);
            return YunkeResult.error("批量删除失败");
        }
    }

    @Override
    public YunkeResult<YunkeAdminVo> getAdminDetail(Long id) {
        try {
            YunkeAdminVo adminVo = adminMapper.selectAdminVoById(id);
            if (adminVo == null) {
                return YunkeResult.error("管理员不存在");
            }
            return YunkeResult.success(adminVo);
        } catch (Exception e) {
            log.error("获取管理员详情失败", e);
            return YunkeResult.error("获取管理员详情失败");
        }
    }

    @Override
    public YunkeResult<IPage<YunkeAdminVo>> getAdminPage(Integer current, Integer size,
                                                   String username, String nickname,
                                                   Integer accountStatus, Long roleId,
                                                   Long departmentId) {
        try {
            Page<YunkeAdminVo> page = new Page<>(current, size);
            IPage<YunkeAdminVo> result = adminMapper.selectAdminPageVo(page, username, nickname,
                    accountStatus, roleId, departmentId);
            return YunkeResult.success(result);
        } catch (Exception e) {
            log.error("分页查询管理员失败", e);
            return YunkeResult.error("查询管理员列表失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> resetPassword(Long id, String newPassword) {
        try {
            YunkeAdmin admin = getById(id);
            if (admin == null) {
                return YunkeResult.error("管理员不存在");
            }

            // 加密新密码
            String hashedPassword = BCrypt.hashpw(newPassword, BCrypt.gensalt());
            admin.setPassword(hashedPassword);
            admin.setPasswordErrorCount(0);
            admin.setUpdateTime(System.currentTimeMillis());

            updateById(admin);
            return YunkeResult.success("密码重置成功");

        } catch (Exception e) {
            log.error("重置密码失败", e);
            return YunkeResult.error("重置密码失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> updateAdminStatus(Long id, Integer accountStatus) {
        try {
            YunkeAdmin admin = getById(id);
            if (admin == null) {
                return YunkeResult.error("管理员不存在");
            }

            // 检查是否为超级管理员
            if (admin.getIsSuperAdmin() && accountStatus != 0) {
                return YunkeResult.error("不能修改超级管理员状态");
            }

            admin.setAccountStatus(accountStatus);
            admin.setUpdateTime(System.currentTimeMillis());
            updateById(admin);

            return YunkeResult.success("状态更新成功");

        } catch (Exception e) {
            log.error("更新管理员状态失败", e);
            return YunkeResult.error("更新状态失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> batchUpdateAdminStatus(List<Long> ids, Integer accountStatus) {
        try {
            adminMapper.batchUpdateStatus(ids, accountStatus, System.currentTimeMillis());
            return YunkeResult.success("批量更新状态成功");
        } catch (Exception e) {
            log.error("批量更新管理员状态失败", e);
            return YunkeResult.error("批量更新状态失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public YunkeResult<Void> unlockAdmin(Long id) {
        try {
            YunkeAdmin admin = getById(id);
            if (admin == null) {
                return YunkeResult.error("管理员不存在");
            }

            admin.setAccountStatus(0);
            admin.setPasswordErrorCount(0);
            admin.setLockExpireTime(null);
            admin.setUpdateTime(System.currentTimeMillis());

            updateById(admin);
            return YunkeResult.success("账户解锁成功");

        } catch (Exception e) {
            log.error("解锁管理员账户失败", e);
            return YunkeResult.error("解锁账户失败");
        }
    }

    @Override
    public YunkeResult<List<String>> getAdminPermissions(Long adminId) {
        try {
            List<String> permissions = adminMapper.selectPermissionsByAdminId(adminId);
            return YunkeResult.success(permissions);
        } catch (Exception e) {
            log.error("获取管理员权限失败", e);
            return YunkeResult.error("获取权限失败");
        }
    }

    @Override
    public boolean existsByUsername(String username, Long excludeId) {
        LambdaQueryWrapper<YunkeAdmin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YunkeAdmin::getUsername, username);
        wrapper.eq(YunkeAdmin::getStatus, 0);
        if (excludeId != null) {
            wrapper.ne(YunkeAdmin::getId, excludeId);
        }
        return count(wrapper) > 0;
    }

    @Override
    public YunkeResult<Long> countAdmins(Integer accountStatus) {
        try {
            Long count = adminMapper.countAdmins(accountStatus);
            return YunkeResult.success(count);
        } catch (Exception e) {
            log.error("统计管理员数量失败", e);
            return YunkeResult.error("统计管理员数量失败");
        }
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp() {
        String ip = request.getHeader("X-Forwarded-For");
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
} 